/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package submarines;

/**
 *
 * @author sshiran
 */
public abstract class Board 
{
    public Square gameBoard[][] = null; //The board is composed  of squares
    public int subsLeft;
    public int[] subs;
    public int[] subsToCreate;
    public int hit;
    /*
     * Board Constractor 
     */
     public Board()
     { 
         subs = Config.SUBMARINES.clone();
         subsToCreate = Config.SUBMARINES.clone();
        gameBoard = new Square [Config.BOARD_SIZE][Config.BOARD_SIZE]; //Set board according to the board size
        for(int i=Config.BOARD_START; i < gameBoard.length + Config.BOARD_START ; i++)
            for(int j=Config.BOARD_START ; j < gameBoard[i].length + Config.BOARD_START; j++)
                 gameBoard[i][j] = new Square(); //Create new square for each place in the board
            this.SidesSquares(); //Set side squares foreach square
            this.subsLeft = 0;
    }

     abstract public Player getPlayerOwner();
     public Square getSquare(int Row, int Col)
     {
         return gameBoard[Row][Col];
     }
     
    private void SidesSquares() //Set sides aquares foreach square
    {
        for(int i=Config.BOARD_START; i < gameBoard.length + Config.BOARD_START ; i++)
            for(int j=Config.BOARD_START ; j < gameBoard[i].length + Config.BOARD_START; j++)
            {
                if(i==0)
                    gameBoard[i][j].setUpSquare(null);
                else
                    gameBoard[i][j].setUpSquare(gameBoard[i-1][j]);

                if(i== gameBoard.length-1)
                    gameBoard[i][j].setDownSquare(null);
                else
                    gameBoard[i][j].setDownSquare(gameBoard[i+1][j]);

                if(j==0)
                    gameBoard[i][j].setLeftSquare(null);
                else
                    gameBoard[i][j].setLeftSquare(gameBoard[i][j-1]);

                if(j==gameBoard.length-1)
                    gameBoard[i][j].setRightSquare(null);
                else
                    gameBoard[i][j].setRightSquare(gameBoard[i][j+1]);
                }
      }
    
    public void removeSubFromSubs(int size)
    {
      subsToCreate[size-1]  --;
    }
    
    public int[] getRemainingSubs() {
        return subsToCreate;
    }

    public int[] getRemainingSubsGame() {
        return subs;
    }
    
     public int getSubsLeft() //Return submarine left on the board
     {
        return this.subsLeft;
     }
 
     public void submarineSunk() //Submarine got out of the board 
     {
         this.subsLeft--;
     }
     
     public void submarineSunk(int size) //Submarine got out of the board 
     {
         this.subsLeft--;
         this.subs[size-1]  --;
     }
     
     public int getSubSize(int row, int col)
     {
         Submarines currShip = gameBoard[row][col].getWhatShip();
         return currShip.getSize();
     }
     
     public boolean removeShip(int row, int col)
     {
        Submarines currShip = gameBoard[row][col].getWhatShip();
        int[] headOfShip = getHeadOfShip(col, row);
        int nCol = headOfShip[0];
        int nRow = headOfShip[1];
        
         if (currShip == null)
         {
             return false;
         }

         for(int i=0; i< currShip.getSize(); i++)
         {
             if(currShip.getDirection() == 2)
             {
                 gameBoard[nRow][nCol].setSign(Config.EMPTY_SQUARE_SIGN);
                 nRow++;
             }
             else
             {
                gameBoard[nRow][nCol].setSign(Config.EMPTY_SQUARE_SIGN);
                nCol++;
            }
         }
         subsToCreate[currShip.getSize() - 1]  ++;         
         subsLeft--;
         return true;
     }
     
     public int getHit()
     {
         return this.hit;
     }
     
     public int isHit(int Row, int Col) //Get square and check if there is submarine on the board
     {
         if(gameBoard[Row][Col].isSquereHit() == true) //if square got hit
         { 
            Submarines currShip = gameBoard[Row][Col].getWhatShip(); //check what ship was hit
            currShip.subWasHit(); //mark ship with hit
            currShip.setIsAlive(); //check if submarine sunk
            if (currShip.getIsAlive() == false)
            {
                this.submarineSunk(currShip.getSize());
                this.hit = currShip.getSize();
                return currShip.getSize();
            }
            this.hit = 0;
            return 0;
         }
         else
         {
             this.hit = -1;
             return -1;
         }
     }

     public boolean anySubsLeft() //If subsLeft number is 0 return no subs on board 
     {
         if (subsLeft == 0)
         {
             return false; //No subs left
         }
         else
         {
             return true; //There is more subs on the board
         }
    }
 
    public void markSpot (int Row, int Col, char ch) //Get square on board and mark it
    {
        this.gameBoard[Row][Col].setSign(ch);
    }
    
    public void cleanBoard() //Put empty sign in all board squares
    {
        for(int i=Config.BOARD_START; i < Config.BOARD_SIZE + Config.BOARD_START ; i++)
            for(int j=Config.BOARD_START ; j < Config.BOARD_SIZE + Config.BOARD_START; j++)
                gameBoard[i][j].setSign(Config.EMPTY_SQUARE_SIGN) ;
    }
   
    public boolean insertShip(int Row,int Col,int shipSize, int direction) //Insert ship to board
    {
        Submarines currShip = new Submarines(shipSize, ""); //create new ship to put on board
        currShip.setDirection(direction);
        
        int currRow = Row;
        int currCol = Col;
         
        if (Row < Config.BOARD_START || Row > Config.BOARD_SIZE - 1 + Config.BOARD_START)  //check if coordinates are on board
        {
            return false;
        }
        
        if (Col < Config.BOARD_START || Col > Config.BOARD_SIZE - 1 + Config.BOARD_START)  //check if coordinates are on board
        {
            return false;
        }
        
        if(gameBoard[currRow][currCol].isSquareTaken() == true) //First check if submarine head is empty
        {
            return false;
        }
         
        if (this.checkSpaceForShip(Row, Col, shipSize, direction) != true) //Check that there is no overlap with other ships
        {
            return false;
        }
        //currShip.setHead(gameBoard[Row][Col]);
        this.subsLeft++; //1 more submarine to board
        gameBoard[currRow][currCol].setSign(Config.SUB_SQUARE_SIGN); //Set first square
        gameBoard[currRow][currCol].setShip(currShip); //set ship on square
        if(direction == 1) //The ship direction is horizontal
        {
             for(int i = 1; i<shipSize;i++) //create ship and put ship sign on squares
             {
                 currCol++;
                 gameBoard[currRow][currCol].setShip(currShip);
                 gameBoard[currRow][currCol].setSign(Config.SUB_SQUARE_SIGN); //Move one square to the right each time and mark it as ship
             }
         }
         else
         {
             for(int i = 1; i<shipSize;i++) //create ship and put ship sign on squares
             {
                 currRow++;
                 gameBoard[currRow][currCol].setShip(currShip);
                 gameBoard[currRow][currCol].setSign(Config.SUB_SQUARE_SIGN);//Move one square down each time and mark it as ship
             }
         }
        removeSubFromSubs(shipSize);
        return true; //All conditions were true and submarine was inserted
    }
  
    public boolean checkSpaceForShip(int Row, int Col, int shipSize, int direction) //Check that there is no overlap between ships
    {
        if (Row < Config.BOARD_START || Row > Config.BOARD_SIZE - 1 + Config.BOARD_START)  //check if coordinates is out of bounds
        {
            return false;
        }
        
        if (Col < Config.BOARD_START || Col > Config.BOARD_SIZE - 1 + Config.BOARD_START)  //check if coordinates is out of bounds
        {
            return false;
        }
        
        if ((Col == Config.BOARD_START || Col == (Config.BOARD_SIZE-1+Config.BOARD_START)) && 
                (Row != Config.BOARD_START && Row != (Config.BOARD_SIZE-1+Config.BOARD_START))) //check if the column is in the edge of board
        {
            return checkShipsColEdge(Row, Col, shipSize, direction);
        }
        else if ((Row == Config.BOARD_START || Row == (Config.BOARD_SIZE-1+Config.BOARD_START)) && 
                (Col != Config.BOARD_START && Col != (Config.BOARD_SIZE-1+Config.BOARD_START))) //check if the row is in the edge of board
        {
            return  checkShipsRowEdge(Row, Col, shipSize, direction);
        }
        else if ((Row == Config.BOARD_START || Row == (Config.BOARD_SIZE-1+Config.BOARD_START)) && 
                (Col == Config.BOARD_START || Col == (Config.BOARD_SIZE-1+Config.BOARD_START))) //check if the coordinates is one of the corners
        {
            return  checkShipsEdges(Row, Col, shipSize, direction);
        }
        else
        {
            return  checkShipsinside(Row, Col, shipSize, direction); //coordinates is in the middle of the board
        }
    }
    
    public boolean checkShipsColEdge(int Row, int Col, int shipSize, int direction)
    {
        if(Col == Config.BOARD_START) { // check all squares near submatine head
            if(this.gameBoard[Row][Col].isSquareTaken()
                    || this.gameBoard[Row][Col].getUpSquare().isSquareTaken()
                    ||this.gameBoard[Row][Col].getUpSquare().getRightSquare().isSquareTaken()
                    ||this.gameBoard[Row][Col].getRightSquare().isSquareTaken()
                    ||this.gameBoard[Row][Col].getRightSquare().getDownSquare().isSquareTaken()
                    ||this.gameBoard[Row][Col].getDownSquare().isSquareTaken())
                    return false;

            if (direction == 2) {// check all squares after head accorsing to the direction
                for(int i= 1; i<shipSize; i++) {
                    Row++;

                    if (Row == Config.BOARD_SIZE - 1)   
                        return true;

                    if(this.gameBoard[Row][Col].isSquareTaken()
                        || this.gameBoard[Row][Col].getUpSquare().isSquareTaken()
                        ||this.gameBoard[Row][Col].getRightSquare().isSquareTaken()
                        ||this.gameBoard[Row][Col].getRightSquare().getDownSquare().isSquareTaken())
                        return false;
                }
                return true;
            } else {
                for(int i= 1; i<shipSize; i++) {// check all squares after head accorsing to the direction
                    Col++;
                    if(this.gameBoard[Row][Col].isSquareTaken()
                        || this.gameBoard[Row][Col].getUpSquare().isSquareTaken()
                        || this.gameBoard[Row][Col].getUpSquare().getRightSquare().isSquareTaken()
                        ||this.gameBoard[Row][Col].getDownSquare().isSquareTaken()
                        ||this.gameBoard[Row][Col].getDownSquare().getRightSquare().isSquareTaken()
                        ||this.gameBoard[Row][Col].getRightSquare().isSquareTaken())
                        return false;
                }
                return true;
            }
        } else {
            if(this.gameBoard[Row][Col].isSquareTaken()
                    || this.gameBoard[Row][Col].getUpSquare().isSquareTaken()
                    ||this.gameBoard[Row][Col].getUpSquare().getLeftSquare().isSquareTaken()
                    ||this.gameBoard[Row][Col].getLeftSquare().isSquareTaken()
                    ||this.gameBoard[Row][Col].getLeftSquare().getDownSquare().isSquareTaken()
                    ||this.gameBoard[Row][Col].getDownSquare().isSquareTaken())
                    return false;

            if (direction == Config.VERTICAL) {//VERTICAL
                for(int i= 1; i<shipSize; i++) {
                    Row++;
                    
                    if (Row == Config.BOARD_SIZE - 1)
                        return true;

                    if(this.gameBoard[Row][Col].isSquareTaken()
                        ||this.gameBoard[Row][Col].getLeftSquare().isSquareTaken()
                        ||this.gameBoard[Row][Col].getDownSquare().isSquareTaken()
                        ||this.gameBoard[Row][Col].getLeftSquare().getDownSquare().isSquareTaken())
                        return false;
                }
                return true;
            }
            return false;
        }
    }

    public boolean checkShipsRowEdge(int Row, int Col, int shipSize, int direction)
    {
        if(Row == Config.BOARD_START) // check all squares near head 
        {
            if(this.gameBoard[Row][Col].isSquareTaken()
                    ||this.gameBoard[Row][Col].getLeftSquare().isSquareTaken()
                    ||this.gameBoard[Row][Col].getLeftSquare().getDownSquare().isSquareTaken()
                    ||this.gameBoard[Row][Col].getDownSquare().isSquareTaken()
                    ||this.gameBoard[Row][Col].getDownSquare().getRightSquare().isSquareTaken()
                    || this.gameBoard[Row][Col].getRightSquare().isSquareTaken())
                    return false;

            if (direction == 2) // check all squares after head accorsing to the direction
            {
                for(int i= 1; i<shipSize; i++)
                {
                    Row++;
                    if(this.gameBoard[Row][Col].isSquareTaken()
                        || this.gameBoard[Row][Col].getDownSquare().isSquareTaken()
                        ||this.gameBoard[Row][Col].getDownSquare().getRightSquare().isSquareTaken()
                        ||this.gameBoard[Row][Col].getDownSquare().getLeftSquare().isSquareTaken())
                        return false;
                }
            }
            else // check all squares after head accorsing to the direction
            {
                for(int i= 1; i<shipSize; i++)
                {
                    Col++;
                    if (Col == Config.BOARD_SIZE - 1)
                    {
                        return true;
                    }
                    if(this.gameBoard[Row][Col].isSquareTaken()
                        || this.gameBoard[Row][Col].getRightSquare().isSquareTaken()
                        || this.gameBoard[Row][Col].getRightSquare().getDownSquare().isSquareTaken())
                        return false;
                }
            }
            return true;
        }
        else
        {
            if(this.gameBoard[Row][Col].isSquareTaken()
                    ||this.gameBoard[Row][Col].getLeftSquare().isSquareTaken()
                    ||this.gameBoard[Row][Col].getUpSquare().isSquareTaken()
                    ||this.gameBoard[Row][Col].getUpSquare().getLeftSquare().isSquareTaken()
                    ||this.gameBoard[Row][Col].getUpSquare().getRightSquare().isSquareTaken()
                    || this.gameBoard[Row][Col].getRightSquare().isSquareTaken())
                    return false;

            if (direction == Config.HORIZONTAL) {
                for(int i= 1; i<shipSize; i++)
                {
                    Col++;
                    if (Col == Config.BOARD_SIZE - 1)
                    {
                        return true;
                    }
                    if(this.gameBoard[Row][Col].isSquareTaken()
                        || this.gameBoard[Row][Col].getRightSquare().isSquareTaken()
                        || this.gameBoard[Row][Col].getRightSquare().getUpSquare().isSquareTaken())
                        return false;
                }
                return true;
            }
            return false;
        }
    }

    public boolean checkShipsEdges(int Row, int Col, int shipSize, int direction)
    {
        if(Col == Config.BOARD_START && Row == Config.BOARD_START) // check all squares near head 
        {
            if(this.gameBoard[Row][Col].isSquareTaken()
                    ||this.gameBoard[Row][Col].getDownSquare().isSquareTaken()
                    ||this.gameBoard[Row][Col].getDownSquare().getRightSquare().isSquareTaken()
                    || this.gameBoard[Row][Col].getRightSquare().isSquareTaken())
                    return false;

            if (direction == 2) //check all squares after head accorsing to the direction
            {
                for(int i= 1; i<shipSize; i++)
                {
                    Row++;
                    if(this.gameBoard[Row][Col].isSquareTaken()
                        || this.gameBoard[Row][Col].getDownSquare().isSquareTaken()
                        ||this.gameBoard[Row][Col].getDownSquare().getRightSquare().isSquareTaken())
                        return false;
                }
                return true;
            }
            else
            {
                for(int i= 1; i<shipSize; i++)
                {
                    Col++;
                    if(this.gameBoard[Row][Col].isSquareTaken()
                        || this.gameBoard[Row][Col].getRightSquare().isSquareTaken()
                        || this.gameBoard[Row][Col].getRightSquare().getDownSquare().isSquareTaken())
                        return false;
                }
                return true;
            }
        }
        if((Col == Config.BOARD_START) && (Row == Config.BOARD_SIZE - 1 + Config.BOARD_START))
        {
            if(this.gameBoard[Row][Col].isSquareTaken()
                    ||this.gameBoard[Row][Col].getUpSquare().isSquareTaken()
                    ||this.gameBoard[Row][Col].getUpSquare().getRightSquare().isSquareTaken()
                    || this.gameBoard[Row][Col].getRightSquare().isSquareTaken())
                    return false;

            for(int i= 1; i<shipSize; i++)
            {
                Col++;
                if(this.gameBoard[Row][Col].isSquareTaken()
                    || this.gameBoard[Row][Col].getRightSquare().isSquareTaken()
                    || this.gameBoard[Row][Col].getRightSquare().getUpSquare().isSquareTaken())
                    return false;
            }    
            return true;
        }
        if((Col == Config.BOARD_SIZE - 1 + Config.BOARD_START) && (Row == Config.BOARD_START))
        {
            if(this.gameBoard[Row][Col].isSquareTaken()
                    ||this.gameBoard[Row][Col].getLeftSquare().isSquareTaken()
                    ||this.gameBoard[Row][Col].getLeftSquare().getDownSquare().isSquareTaken()
                    || this.gameBoard[Row][Col].getDownSquare().isSquareTaken())
                    return false;
            
            for(int i= 1; i<shipSize; i++)
            {
                Row++;
               if(this.gameBoard[Row][Col].isSquareTaken()
                || this.gameBoard[Row][Col].getDownSquare().isSquareTaken()
                || this.gameBoard[Row][Col].getDownSquare().getLeftSquare().isSquareTaken())
                return false;
            }    
            return true;
        }
         
        if((Col == Config.BOARD_SIZE - 1 + Config.BOARD_START) && (Row == Config.BOARD_SIZE - 1 + Config.BOARD_START))
        {
                return false;
        }    
        return true;
    }
   
    public boolean checkShipsinside(int Row, int Col, int shipSize, int direction)
    {
        if(this.gameBoard[Row][Col].isSquareTaken()
            ||this.gameBoard[Row][Col].getUpSquare().isSquareTaken()
            ||this.gameBoard[Row][Col].getUpSquare().getLeftSquare().isSquareTaken()
            ||this.gameBoard[Row][Col].getUpSquare().getRightSquare().isSquareTaken()
            || this.gameBoard[Row][Col].getLeftSquare().isSquareTaken()
            || this.gameBoard[Row][Col].getRightSquare().isSquareTaken()
            || this.gameBoard[Row][Col].getDownSquare().isSquareTaken()
            || this.gameBoard[Row][Col].getDownSquare().getLeftSquare().isSquareTaken()
            || this.gameBoard[Row][Col].getDownSquare().getRightSquare().isSquareTaken())
            return false;
        
        if(direction ==2 ) // check all squares after head accorsing to the direction
        {
            for(int i= 1; i<shipSize; i++)
            {
                Row++;
                if (Row == Config.BOARD_SIZE - 1 + Config.BOARD_START)
                {
                    if (Row == Config.BOARD_SIZE - 1 + Config.BOARD_START && i == shipSize-1)
                    {
                        return true;
                    }
                    return false;
                }
                if(this.gameBoard[Row][Col].isSquareTaken()
                    || this.gameBoard[Row][Col].getDownSquare().isSquareTaken()
                    ||this.gameBoard[Row][Col].getDownSquare().getRightSquare().isSquareTaken()
                    ||this.gameBoard[Row][Col].getDownSquare().getLeftSquare().isSquareTaken())
                    return false;
            }
            return true;
        }    
        else // check all squares after head accorsing to the direction
        {
            for(int i= 1; i<shipSize; i++)
            {
                Col++;
                if (Col == Config.BOARD_SIZE - 1 + Config.BOARD_START)
                {
                    if (Col == Config.BOARD_SIZE - 1 + Config.BOARD_START && i == shipSize-1)
                    {
                        return true;
                    }
                    return false;
                }
                if(this.gameBoard[Row][Col].isSquareTaken()
                    || this.gameBoard[Row][Col].getRightSquare().isSquareTaken()
                    ||this.gameBoard[Row][Col].getRightSquare().getDownSquare().isSquareTaken()
                    ||this.gameBoard[Row][Col].getRightSquare().getUpSquare().isSquareTaken())
                    return false;   
            }
        }
        return true;
    }
    
    public int[] getHeadOfShip(int col, int row) {
        int[] coords = null;
        Submarines s = gameBoard[row][col].getWhatShip();
        if (s != null) {
            int dir = s.getDirection();
            if (dir == Config.HORIZONTAL)
                while ((col > Config.BOARD_START) && ((gameBoard[row][col - 1].getSign() == Config.HIT_SQUARE_SIGN) || (gameBoard[row][col - 1].getSign() == Config.SUB_SQUARE_SIGN)))
                    col--;
            if (dir == Config.VERTICAL)
                while ((row > Config.BOARD_START) && ((gameBoard[row - 1][col].getSign() == Config.HIT_SQUARE_SIGN) || (gameBoard[row - 1][col].getSign() == Config.SUB_SQUARE_SIGN)))
                    row--;
            coords = new int[2];
            coords[0] = col;
            coords[1] = row;
        }
        return coords;
    }
}
